package com.hc.summary.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.core.graphics.PathParser;

import com.hc.summary.R;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class SVGView extends View {
    private Context mContext;
    private ThreadPoolExecutor mThreadPoolExecutor;
    private List<PathBean> mBeans;
    private Paint mPaint;
    private RectF mMaxRectF;
    private float mScale;

    private PathBean mTouchPathBean;
    public SVGView(Context context) {
        super(context);
    }

    public SVGView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        loadSVG(context);
    }

    public SVGView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize =MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(MeasureSpec.makeMeasureSpec(widthSize,MeasureSpec.EXACTLY)
                            ,MeasureSpec.makeMeasureSpec(heightSize,MeasureSpec.EXACTLY));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(mMaxRectF != null){
            mScale = getWidth() / mMaxRectF.width();
        }
        if(mBeans != null && !mBeans.isEmpty()){
            canvas.save();
            canvas.scale(mScale,mScale);
            for(PathBean bean:mBeans){
                bean.drawSelf(canvas,mPaint,false);
            }
            if(mTouchPathBean != null){
                mTouchPathBean.drawSelf(canvas,mPaint,true);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        handleTouchEvent(event.getX(),event.getY());
        return super.onTouchEvent(event);
    }

    private void handleTouchEvent(float x,float y){
        if(mBeans ==null){
            return;
        }
        PathBean pathBean=null;
        for(PathBean bean:mBeans){
            if(bean.isTouch(x/mScale,y/mScale)){
                pathBean = bean;
                break;
            }
        }
        if(mTouchPathBean!=null){
            if(pathBean !=null){
                if(mTouchPathBean.mPath==pathBean.mPath){
                    mTouchPathBean = null;
                    postInvalidate();
                }else {
                    mTouchPathBean = pathBean;
                    postInvalidate();
                }
            }
        }else {
            if(pathBean!=null){
                mTouchPathBean = pathBean;
                postInvalidate();
            }
        }
    }
    private void loadSVG(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        initThreadPool();
        initSVG();
    }

    private void initSVG() {
        if(mThreadPoolExecutor != null){
            mThreadPoolExecutor.execute(() -> {
                InputStream inputStream = mContext.getResources().openRawResource(R.raw.china);
                try {
                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder builder = factory.newDocumentBuilder();
                    Document document = builder.parse(inputStream);
                    Element rootElement = document.getDocumentElement();
                    NodeList elements = rootElement.getElementsByTagName("path");
                    List<PathBean> beans = new ArrayList<>();
                    float top = -1;
                    float bottom = -1;
                    float left = -1;
                    float right = -1;
                    for (int i = 0; i < elements.getLength(); i++) {
                        Element element = (Element) elements.item(i);
                        String pathData = element.getAttribute("android:pathData");
                        Path path = PathParser.createPathFromPathData(pathData);
                        PathBean bean = new PathBean(path);
                        beans.add(bean);
                        RectF rectF = new RectF();
                        path.computeBounds(rectF,true);
                        top = top == -1?rectF.top:Math.min(top,rectF.top);
                        bottom = bottom==-1?rectF.bottom:Math.max(bottom,rectF.bottom);
                        left = left == -1?rectF.left:Math.min(left,rectF.left);
                        right = right==-1?rectF.right:Math.max(right,rectF.right);
                    }
                    mMaxRectF = new RectF(left,top,right,bottom);
                    mBeans = beans;
                    if(!mBeans.isEmpty()){
                        for (int i = 0; i < mBeans.size(); i++) {
                            int m = i % 4;
                            int color;
                            if(m==1){
                                color = 0xFF239bd7;
                            }else if(m==2){
                                color = 0xFF30A9E5;
                            }else if(m==3){
                                color = 0xFF80CBF1;
                            }else{
                                color = 0xFF00FFFF;
                            }
                            mBeans.get(i).setColor(color);
                        }
                        post(() -> postInvalidate());
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    try {
                        if(inputStream != null){
                            inputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private void initThreadPool(){
        mThreadPoolExecutor = new ThreadPoolExecutor(1, 1, 10L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setPriority(Thread.MAX_PRIORITY);
                return thread;
            }
        }, new ThreadPoolExecutor.AbortPolicy());
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if(mThreadPoolExecutor != null){
            mThreadPoolExecutor.shutdown();
        }
    }

    private static class PathBean{
        private Path mPath;
        private int mColor;

        public PathBean(Path path) {
            this.mPath = path;
        }

        public void setColor(int color) {
            this.mColor = color;
        }

        public void drawSelf(Canvas canvas, Paint paint,boolean isTouch){
            if(isTouch){
                paint.clearShadowLayer();
                paint.setStrokeWidth(1);
                paint.setStyle(Paint.Style.FILL);
                paint.setColor(mColor);
                canvas.drawPath(mPath,paint);
                paint.setStyle(Paint.Style.STROKE);
                paint.setColor(0xFFFF0000);
                canvas.drawPath(mPath,paint);
            }else {
                paint.setStrokeWidth(2);
                paint.setColor(Color.BLACK);
                paint.setStyle(Paint.Style.FILL);
                paint.setShadowLayer(8,0,0,0xffffff);
                canvas.drawPath(mPath,paint);

                paint.clearShadowLayer();
                paint.setColor(mColor);
                paint.setStyle(Paint.Style.FILL);
                paint.setStrokeWidth(2);
                canvas.drawPath(mPath,paint);
            }
        }

        public boolean isTouch(float x,float y){
            RectF rectF = new RectF();
            mPath.computeBounds(rectF,true);
            Region region = new Region();
            region.setPath(mPath,new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
            return region.contains((int) x, (int) y);
        }
    }
}
